package org.tlang.parser;

import org.tlang.ast.AST;
import org.tlang.ast.ASTLeaf;
import org.tlang.ast.leaf.*;
import org.tlang.ast.list.expr.UnaryExpr;
import org.tlang.exception.ParseException;
import org.tlang.lexer.Lexer;
import org.tlang.lexer.token.Token;

import java.util.Arrays;

public abstract class Parser {
    protected Lexer lexer;

    public Parser(Lexer lexer) {
        this.lexer = lexer;
    }

    /**
     * 判断是否匹配标识符序列
     *
     * @param names 标识符名称序列
     */
    protected boolean isIdentifier(String... names) {
        int i = 0;
        for (String name : names) {
            Token token = lexer.peek(i++);
            if (!token.isIdentifier() || !name.equals(token.getText())) {
                return false;
            }
        }
        return true;
    }

    /**
     * 跳过一个指定标识符名称的token
     *
     * @param name 标识符名称
     */
    protected void skip(String name) throws ParseException {
        Token token = lexer.poll();
        if (token.isIdentifier() && name.equals(token.getText())) {
            return;
        }

        throw new ParseException("expect \"" + name + "\"", token);
    }

    /**
     * 解析一个合法的标识符
     */
    protected AST identifier() throws ParseException {
        Token token = lexer.poll();
        if (token.isIdentifier()) {
            return new Name(token);
        }

        throw new ParseException("bad identifier", token);
    }

    /**
     * primary: "(" expr ")" | STRING | INTEGER | IDENTIFIER
     */
    protected AST primary() throws ParseException {
        if (isIdentifier("(")) {
            skip("(");
            AST expr = expr();
            skip(")");
            return expr;
        } else {
            Token token = lexer.peek(0);
            if (token.isInteger()) {
                return new I64Literal(lexer.poll());
            } else if (token.isString()) {
                return new StrLiteral(lexer.poll());
            } else if (token.isBool()) {
                return new BoolLiteral(lexer.poll());
            } else if (token.isFloat()) {
                return new F64Literal(lexer.poll());
            } else {
                return identifier();
            }
        }
    }

    /**
     * factor: ("-" | "!") primary | primary
     */
    protected AST factor() throws ParseException {
        if (isIdentifier("-") || isIdentifier("!")) {
            AST op = new ASTLeaf(lexer.poll());
            return new UnaryExpr(Arrays.asList(op, primary()));
        } else {
            return primary();
        }
    }

    protected abstract AST expr() throws ParseException;

    public abstract AST parse(Lexer lexer) throws ParseException;
}
